<?php
/**
 * Arrow template linker ( for template tags ) 
 * 
 * @version 1.0
 * @license  GNU GPL
 * @author Artur Kmera <artur.kmera@arrowplatform.org> 
 */
ArrowController::importModel("controls.IArrowControlsManager");

class ArrowTemplateLinker implements IArrowControlsManager{

	/**
	 * Included beans ( if we want to use bean mor than one time we include class only once)
	 * 
	 * @var Array
	 */
	private $includedBeans = array();
	
	private $includedModels = array();
	
	const INSERT_AT_BEGINING = 0;
	const INSERT_INLINE = 1;
	
	const HTM_AMP = "&amp;";
	const AMP = "&";
	
	private $codeInsertMode = self::INSERT_AT_BEGINING;
	
	
	/**
	 * Instance
	 * 
	 * @var ArrowTemplateLinker
	 */
	private static  $selfInstance = null;

	/**
	 * Singleton !NO_REMOTE
	 * 
	 * @return ArrowTemplateLinker
	 */
	public static function getDefault( ) {
		if (self :: $selfInstance == null ) {
			self :: $selfInstance = new ArrowTemplateLinker();
		}
		return self :: $selfInstance;
	}
	
	/**
	 * Constructor 
	 */
	public function __construct(){
	}
	
	
	public function setInsertMode( $mode ){
    	$this->codeInsertMode = $mode;
	}
	
	public function getControlVersionsConf($prefix,$tag){
		if($tag == "bean"){
			return array(
				"bean" => array(
					"params" => array(
						"path", "_htmlAmp"
					)
				) 
			);
		}
		if($tag == "template"){
			return array(
				"template" => array(
					"params" => array(
						"path", "_htmlAmp"
					)
				) 
			);
			
		}
	}
	
	/**
	 * Handle for template call:template tags
	 *
	 * @param array $args
	 * @param boolean $useLiteral If true return content in {literal} tag
	 * @return String
	 */
	public function handleTemplateCall($args, $useLiteral = true){
		if( !isset( $args["path"] ) )
			throw new ArrowTemplatesException( array( "msg" => "Call temlate, path not passer") );
		
		$tmp = explode( "::", $args["path"] );
		try{
			$template = ArrowController::$activeProject->getTemplatesStructure()->findTemplate(array( "path"=> $tmp[0], "name" => $tmp[1] ));
			$pageClass = $template->getPageClass();
			$pageClass->createPage();
			$pageClass->createView();

			if($useLiteral){
				$ret = "{literal}".$pageClass->display()."{/literal}";
			}else{
				$ret = $pageClass->display(); 
			}
			return $ret;
		}catch(ArrowTemplatesException $error){
				throw new ArrowTemplatesException( array( "msg" => "Call temlate, template not found", "path" => $tmp[0], "name" => $tmp[1] ) );
		}
		
	}
	
	/**
	 * Handle for template link:template tags
	 *
	 * @param String[] $args
	 * @return String
	 */	
	public function generateTemplateLink( $args){

		$request = ArrowRequestContext::getDefault();
		if( isset( $request[ArrowRouter::PROJECT_PARAMETER] ) )
			$args[ArrowRouter::PROJECT_PARAMETER] = $request[ArrowRouter::PROJECT_PARAMETER];
		
		$link = ArrowRouter::$INDEX_FILE;
		$template = ArrowRouter::getDefault()->getTemplate();
		if( isset( $args["path"] ) ){
			$tmp = explode( "::", $args["path"] );
			if(count($tmp) != 2)
				throw new ArrowTemplatesException( array( "msg" => "Wrong template path format", "path" => $args["path"] ) );
			try{
				$targetTemplate = $template->getTemplatesStructure()->findTemplate(array( "path"=> $tmp[0], "name" => $tmp[1] ));
			}catch(ArrowTemplatesException $error){
				throw new ArrowTemplatesException( array( "msg" => "Link template, template not found: {$tmp[0]}::{$tmp[1]}", "path" => $tmp[0], "name" => $tmp[1] ) );
			}
		}else{
			$targetTemplate = $template;
		}
		unset( $args["path"] );


		$link.= "?".ArrowRouter::TEMPLATE_PARAMETER."=".$targetTemplate->getId();
		if(isset($args["_htmlAmp"])){
			$tmp = $args["_htmlAmp"];
			unset($args["_htmlAmp"]);
			$link.= $this->prepareArgs( $args, $tmp );
		}else{
			$link.= $this->prepareArgs( $args );	
		}
		return $link;
	}
	
	
	
	
	
	/**
	 * Handle for template link:bean tags
	 *
	 * @param String[] $args
	 * @return String
	 */
	public function generateBeanLinkHandle( $args ){
		return $this->generateBeanLink($args);
	}
	
	/**
	 * Bean link generator
	 * @param array $args
	 * @param boolean $remote
	 * @return string
	 */
	public function generateBeanLink( $args, $remote = false){
		$link = ArrowRouter::$INDEX_FILE;
		if( !isset( $args["path"] ) )
			throw new ArrowTemplatesException("Action link: no path given");

		$tmp = explode("::", $args["path"]);
		$bean = ArrowRouter::getDefault()->getProject()->getBeansStructure()->findBean(array( "path" => $tmp[0], "name" => $tmp[1] ));

		if( $bean->getType() != ArrowBeanDescriptor::ACTION_BEAN && !$remote )
			throw  new ArrowTemplatesException(array( "msg" => "Action link: path to no action bean", "path" => $args["path"] ));

		if( $remote )
			$link.= "?".ArrowRouter::DATA_REQUEST_PARAMETER."=".$bean->getId();
		else
			$link.= "?".ArrowRouter::ACTION_BEAN_PARAMETER."=".$bean->getId();
			
		unset( $args["path"] );


		//Generating return tpl parameter
		$template = ArrowRouter::getDefault()->getTemplate();
		if( isset( $args["return_tpl"] ) ){
			$tmp = explode( "::", $args["return_tpl"] );
			$targetTemplate = $template->getTemplatesStructure()->findTemplate(array( "path"=> $tmp[0], "name" => $tmp[1] ));
		}else{
			$targetTemplate = $template;
		}
		unset( $args["return_tpl"] );

		$args[ArrowRouter::TEMPLATE_PARAMETER] = $targetTemplate->getId();

		if(isset($args["_htmlAmp"])){
			$tmp = $args["_htmlAmp"];
			unset($args["_htmlAmp"]);
			$link.= $this->prepareArgs( $args, $tmp );
		}else{
			$link.= $this->prepareArgs( $args );	
		}
		
		return $link;
	}
	
	
	/**
	 * Handle for template link:beanRemoteAccess
	 * @param String[] $args
	 * @return String
	 */
	public function generateBeanRemoteAccesLink( $args, $in ){
		return $this->generateBeanLink( $args, $in, true );
	}

	/**
	 * Handle for template call:bean tags
	 *
	 * @param unknown_type $args
	 * @return mixed
	 */
	public function handleBeanCall( $args ){
		
		if( !isset( $args["path"] ) )
			throw new ArrowTemplatesException("Action link: no path given");
			
		$tmp = explode("::", $args["path"]);
		$bean = ArrowRouter::getDefault()->getProject()->getBeansStructure()->findBean(array( "path" => $tmp[0], "name" => $tmp[1] ));

		if( $bean->getType() != ArrowBeanDescriptor::VIEW_HELPER_BEAN )
		throw  new ArrowTemplatesException(array( "msg" => "Cannot call non viewHelperBean from template context", "path" => $args["path"] ));

		unset( $args["path"] );

		/**
		 * generowanie parametrow
		 */
		$data = "array( ";
		foreach( $args as $key => $val ){

			$data.='"'.$key.'" => ';
			if ( substr( $val, 0, 1 ) == '{' ){
				if( strpos( $val, "."  ) !== false ){
					$tmp = explode( "." ,substr( $val, 2, -1 ) );
					$data.='$this->_tpl_vars[ "'.implode( '" ][ "', $tmp ).'" ],';

				}else{
					$data.='$this->_tpl_vars[ "'.substr( $val, 2, -1 ).'" ],';
				}
			}else{
				$data.= "'$val',";
			}
		}
		$data = rtrim( $data, "," );
		$data.= ") ";

		//TODO Kasy maja byc wstawiane na poczatku pliku poniewaz kiedy sa w petli do sie deklaruja ilestam razy
		//zmienic to i usunac if( class_exists())
		
		$call = "";
		if( !in_array( $bean->getId(), $this->includedBeans ) ){
			$this->includedBeans[] = $bean->getId();
			$this->phpCode.= $bean->getSource(); 
		}
			
		$call.= ' $tmp = ArrowController::getBeanInstance( '.$bean->getId()."); ";
		if( isset( $args["assign"] ) ){
			$call.= '$this->_tpl_vars["'.$args["assign"].'"] = $tmp->supply( '.$data.' );';
			unset( $args["assign"] );
		}
		
		
		return "{php}".$call."{/php}";
	}
	
		/**
	 * Handle for template call:model tags
	 *
	 * @param unknown_type $args
	 * @return mixed
	 * @todo make exepctions
	 */
	public function handleModelCall( $args ){
		$str = "{php}";
		$str.= '$this->_tpl_vars["'.$args["assign"].'"] = $model'."=ArrowController::getModelInstance(\"".$args["model"]."\")";
		$str.= "{/php}";
		return $str;
	}
	
	
	
	public function returnProjectRoot(){
		return ARROW_PROJECTS_PATH.ArrowRouter::getDefault()->getProject()->getPath();
	}
	
	/**
	 * Generates standard link
	 *
	 * @param String $templatePath Template path
	 * @param String $$beanPath Action path
	 * @param Array $args Arguments
	 * @param String $mediatorName Mediator name
	 * @return String
	 */
	public function generateStandardLink( $templatePath, $beanPath = false, $args = array(), $mediatorName = false ){

		if( $templatePath  ){
			$tmpTemplate = explode("::", $templatePath);
			try{
				$template = ArrowRouter::getDefault()->getProject()->getTemplatesStructure()->findTemplate(array("path" => $tmpTemplate[0], "name" => $tmpTemplate[1]));
			}catch(ArrowTemplatesException $error){
				throw new ArrowTemplatesException( array( "msg" => "Link temlate, template not found", "path" => $tmp[0], "name" => $tmp[1] ) );
			}
		}else{
			$template = ArrowRouter::getDefault()->getTemplate();
		}

		$link = ArrowRouter::$INDEX_FILE."?".ArrowRouter::TEMPLATE_PARAMETER."=".$template->getId();

		if( $beanPath ){
			$tmpBean = explode("::", $beanPath);
			$bean = ArrowRouter::getDefault()->getProject()->getBeansStructure()->findBean(array("path" => $tmpBean[0], "name" => $tmpBean[1]));
			$args[ArrowRouter::ACTION_BEAN_PARAMETER] = $bean->getId();
		}
		if( $mediatorName ){
			$args[ArrowRouter::MEDIATOR_PARAMETER] = $mediatorName;
		}
		if( !empty($args) ){
			$link.= $this->prepareArgs($args);
		}
		
		return $link;
	}
	
	/**
	 * Preparing arguments for link	
	 *
	 * @param Array $args
	 * @return String
	 */
	private function prepareArgs( $args, $useHTMLAmp = true ){
		if( $useHTMLAmp )
			$amp = self::HTM_AMP;
		else
			$amp = self::AMP;
		$link = "";
		foreach( $args as $key => $val ){
			$link.= $amp.$key."=".$val;
		}
		return $link;
	}
	
}
?>
